﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Wise.Util.Queryable
{
    /// <summary>
    /// 弱约束字典
    /// 
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    /// <remarks>
    /// 因为是使用new隐藏Add 等方法
    /// ，所以，不要将WeekDictionary隐式转换成Dictionary使用
    /// 。否则，会调用Dictionary的方法
    /// </remarks>
    public class _WeekDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        /// <summary>
        /// 锁
        /// </summary>
        internal readonly Object _Locker = new object();

        /// <summary>
        /// 隐藏ADD
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        private new void Add(TKey key, TValue value)
        {

        }

        /// <summary>
        /// 增加或修改项
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public virtual bool AddOrSet(TKey key, TValue value)
        {
            if (Monitor.TryEnter(_Locker, 10))
            {
                try
                {
                    if (this.ContainsKey(key))
                    {
                        this.Remove(key);
                    }
                    base.Add(key, value);
                    return true;
                }
                finally
                {
                    Monitor.Exit(_Locker);
                }
            }
            return false;

        }

        /// <summary>
        /// 获取或者设置
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public new virtual TValue this[TKey key]
        {
            get
            {
                return this.TryGet(key);
            }
            set
            {
                this.AddOrSet(key, value);
            }
        }

        /// <summary>
        /// 获取
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual TValue TryGet(TKey key)
        {
            if (this.ContainsKey(key) && Monitor.TryEnter(_Locker))
            {
                try
                {
                    return base[key];
                }
                finally
                {
                    Monitor.Exit(_Locker);
                }
            }
            return ObjectHelper.CreateInstance<TValue>();
        }

        /// <summary>
        /// 试图移除键值对，不论是否存在
        /// </summary>
        /// <param name="key"></param>
        public virtual void TryRemove(TKey key)
        {
            if (this.ContainsKey(key) && Monitor.TryEnter(_Locker))
            {
                try
                {
                    this.Remove(key);
                }
                finally
                {
                    Monitor.Exit(_Locker);
                }
            }
        }

        /// <summary>
        /// 移除所有项
        /// </summary>
        public new void Clear()
        {
            if (Monitor.TryEnter(_Locker))
            {

                try
                {
                    base.Clear();
                }
                finally
                {
                    Monitor.Exit(_Locker);
                }

            }
        }

        /// <summary>
        /// 获取值
        /// </summary>
        /// <returns></returns>
        public TValue GetOrCreate(TKey key, Func<TValue> onexpied)
        {
            if (this.ContainsKey(key))
            {
                if (Monitor.TryEnter(_Locker))
                {
                    try
                    {
                        return this[key];
                    }
                    finally
                    {
                        Monitor.Exit(_Locker);
                    }
                }

            }
            if (onexpied != null)
            {
                this.AddOrSet(key, onexpied());
                return this.TryGet(key);
            }
            TValue value = ObjectHelper.CreateInstance<TValue>();
            this.AddOrSet(key, value);
            return value;
        }
    }
}
